﻿#region References

using System;
using System.Collections.Generic;
using System.Linq;
using App_Code.Objects;
using VisualCron;
using VisualCronAPI;

#endregion

namespace App_Code.Logic
{
    /// <summary>
    /// Summary description for VCLogic
    /// </summary>
    public class VisualCronLogic
    {
        public static List<VisualCronSession> VisualCronSessions = new List<VisualCronSession>();

        #region Constructor
        static VisualCronLogic()
        {
            Client.EventOnConnectedStatic += new Client.DelegateOnConnected(Client_EventOnConnectedStatic);
            Client.EventOnDisconnectStatic += new Client.DelegateOnDisconnect(Client_EventOnDisconnectStatic);
            Client.EventOnSyncComplete += new Client.DelegateOnSyncComplete(Client_EventOnSyncComplete);
            Jobs.JobAddedStatic += new Jobs.DelegateJobAdded(Jobs_JobAddedStatic);
            Jobs.JobRemovedStatic += new Jobs.DelegateOnJobRemoved(Jobs_JobRemovedStatic);
            Jobs.JobUpdatedStatic += new Jobs.DelegateJobUpdated(Jobs_JobUpdatedStatic);
            Tasks.TaskAddedStatic += new Tasks.DelegateTaskAdded(Tasks_TaskAddedStatic);
            Tasks.TaskRemovedStatic += new Tasks.DelegateTaskRemoved(Tasks_TaskRemovedStatic);
            Tasks.TaskUpdatedStatic += new Tasks.DelegateOnTaskUpdated(Tasks_TaskUpdatedStatic);
        }
        #endregion

        #region Public methods
        public static VisualCronSession AddSession(string sessionId)
        {
            RemoveSession(sessionId);

            var session = new VisualCronSession { AspNetSessionId = sessionId };
            VisualCronSessions.Add(session);

            return session;
        }

        public static void CloseConnections(VisualCronSession session)
        {
            if (session != null)
            {
                foreach (var server in session.Servers.ToList())
                // ToList() creates a copy of collection through which we iterate, while Disconnect() is removing items from original collection
                {
                    Disconnect(session, server.UserServerId);
                }
            }
        }

        public static void RemoveSession(string sessionId)
        {
            var session = VisualCronSessions.Find(x => x.AspNetSessionId == sessionId);

            CloseConnections(session);

            VisualCronSessions.RemoveAll(x => x.AspNetSessionId == sessionId);
        }

        public static VisualCronSession GetByUserServerId(string userServerId)
        {
            return VisualCronSessions.Find(x => x.Servers.Exists(s => s.UserServerId == userServerId));
        }

        public static Server GetServerByUserServerId(VisualCronSession session, string userServerId)
        {
            return session.Servers.Find(s => s.UserServerId == userServerId);
        }


        public static VisualCronSession GetByClientId(string clientId)
        {
            return VisualCronLogic.VisualCronSessions.Find(x => x.SignalRClientId == clientId);
        }

        public static Server Connect(string address, string userName, string password, VisualCronSession vcVisualCronSession, bool isLocal, string connectionId, bool useCompression)
        {
            try
            {
                var conn = new Connection
                               {
                                   ConnectionType =
                                       isLocal ? Connection.ConnectionT.Local : Connection.ConnectionT.Remote,
                                   Address = address,
                                   UserName = userName,
                                   PassWord = password,
                                   UseCompression = useCompression,
                                   ClientType = ClientConnectionClass.ClientT.WebClient
                               };

                var server = vcVisualCronSession.Client.Connect(conn);

                ConnectionLogic.ServerConnectionAdded(vcVisualCronSession, connectionId, server.UserServerId);

                //this isn't correct to do this here - should be in Connected event, but it fires before we assign UserServerId to Connection
                ConnectionLogic.ServerConnectionStateChanged(vcVisualCronSession, server.UserServerId, true);

                return server;
            }
            catch (Exception exc)
            {
                bool isLoginError = IsLoginError(exc);

                vcVisualCronSession.Connection_Error(connectionId, isLoginError, exc.Message);
                return null;
            }
        }

        public static bool Disconnect(VisualCronSession session, string userServerId)
        {
            var server = GetServerByUserServerId(session, userServerId);

            if (server != null)
            {
                server.Disconnect();
                return true;
            }

            return false;
        }

        public static void JobActivate(VisualCronSession session, string userServerId, string jobId)
        {
            var server = GetServerByUserServerId(session, userServerId);

            server.Jobs.ActivateAsync(jobId);
        }

        public static void JobDeactivate(VisualCronSession session, string userServerId, string jobId)
        {
            var server = GetServerByUserServerId(session, userServerId);

            server.Jobs.DeActivateAsync(jobId);
        }

        public static void JobStop(VisualCronSession session, string userServerId, string jobId)
        {
            var server = GetServerByUserServerId(session, userServerId);

            server.Processes.KillJobProcesses(jobId);

        }

        public static void JobStart(VisualCronSession session, string userServerId, string jobId, string taskId)
        {
            var server = GetServerByUserServerId(session, userServerId);

            server.Jobs.Run(jobId, false, false, false, taskId);
        }

        public static void TaskActivate(VisualCronSession session, string userServerId, string taskId)
        {
            var server = GetServerByUserServerId(session, userServerId);

            server.Jobs.Tasks.ActivateAsync(taskId);
        }

        public static void TaskDeactivate(VisualCronSession session, string userServerId, string taskId)
        {
            var server = GetServerByUserServerId(session, userServerId);

            server.Jobs.Tasks.DeActivateAsync(taskId);

        }

        public static void TaskStop(VisualCronSession session, string userServerId, string jobId, string taskId)
        {
            var server = GetServerByUserServerId(session, userServerId);

            //server.Processes.KillTaskProcess(new KillVCProcessClass() { TaskId = taskId, JobId = jobId, KillType = KillVCProcessClass.VCKillT.KillTaskProcess });

            server.Processes.KillTaskProcesses(jobId,taskId);

        }

        public static void TaskStart(VisualCronSession session, string userServerId, string jobId, string taskId)
        {
            var server = GetServerByUserServerId(session, userServerId);

            server.Jobs.Tasks.Run(jobId, taskId, false, false, false);
        }

        public static bool IsTaskRunning(Server server, TaskClass task)
        {
            return task.Stats.Status == TaskStatsClass.TaskStatusT.Running;
            //return server.Processes.IsTaskRunning(task);
        }
        #endregion

        #region Event handlers

        static void Client_EventOnSyncComplete(Client c, ref Server s)
        {
            var vcSession = VisualCronSessions.Find(x => x.Client.Id == c.Id);

            if (vcSession != null)
            {
                vcSession.GetServerSynchronized(s.UserServerId).Set();
             
                // we've been calling this before instead of Connected event, but now it seems to fire ok, so commenting
                //vcSession.Client_EventOnConnected(c, ref s);
            }
        }

        static void Client_EventOnConnectedStatic(Client c, ref Server s)
        {
            //don't do anything in this event now as Client_EventOnSyncComplete is used instead
        }

        static void Client_EventOnDisconnectStatic(Client c, ref Server s, bool bolIsException, string strError)
        {
            var vcSession = VisualCronSessions.Find(x => x.Client.Id == c.Id);

            if (vcSession != null)
            {
                vcSession.Client_EventOnDisconnect(c, ref s, bolIsException, strError);

                ConnectionLogic.ServerConnectionStateChanged(vcSession, s.UserServerId, false);
            }
        }

        static void Jobs_JobAddedStatic(ref Server server, VisualCron.JobClass j)
        {
            var serverId = server.UserServerId;
            var vcSession = VisualCronSessions.Find(x => x.Servers.Exists(s => s.UserServerId == serverId));

            if (vcSession != null)
            {
                vcSession.Job_Added(serverId, j);
            }
        }

        static void Jobs_JobRemovedStatic(ref Server server, VisualCron.JobClass j)
        {
            var vcSession = GetByUserServerId(server.UserServerId);

            if (vcSession != null)
            {
                vcSession.Job_Removed(server.UserServerId, j);
            }
        }

        static void Jobs_JobUpdatedStatic(ref Server server, VisualCron.JobClass j)
        {
            var vcSession = GetByUserServerId(server.UserServerId);

            if (vcSession != null)
            {
                vcSession.Job_Updated(server.UserServerId, j);
            }

        }

        static void Tasks_TaskAddedStatic(ref Server server, VisualCron.JobClass j, VisualCron.TaskClass t)
        {
            var vcSession = GetByUserServerId(server.UserServerId);

            if (vcSession != null)
            {
                vcSession.Task_Added(server.UserServerId, j.Id, t, IsTaskRunning(server, t));
            }
        }

        static void Tasks_TaskRemovedStatic(ref Server server, VisualCron.JobClass j, VisualCron.TaskClass t)
        {
            var vcSession = GetByUserServerId(server.UserServerId);

            if (vcSession != null)
            {
                vcSession.Task_Removed(server.UserServerId, j.Id, t, IsTaskRunning(server, t));
            }
        }

        static void Tasks_TaskUpdatedStatic(ref Server server, VisualCron.JobClass j, VisualCron.TaskClass t)
        {
            var vcSession = GetByUserServerId(server.UserServerId);

            if (vcSession != null)
            {
                vcSession.Task_Updated(server.UserServerId, j.Id, t, IsTaskRunning(server, t));
            }
        }
        #endregion

        #region Private methods

        private static bool IsLoginError(Exception exc)
        {
                if (exc is Client.ClientLoginFailedException)
                {
                    var loginExc = (exc as Client.ClientLoginFailedException);

                    switch (loginExc.LoginResult.LoginResult)
                    {
                        case LoginResultClass.ResultT.WrongPassWord:
                        case LoginResultClass.ResultT.Inactive:
                        case LoginResultClass.ResultT.NoSuchUser:
                            return true;
                        default:
                            return false;
                    }
                }

            return false;
        }

        #endregion
    }
}